package org.yun.worker;


import com.alibaba.fastjson.JSON;
import com.google.common.util.concurrent.AtomicLongMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.yun.biz.dao.CouponRepository;
import org.yun.biz.model.Coupon;
import org.yun.config.IConfig;
import org.yun.constants.Constant;
import org.yun.util.RedisUtil;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;

import static org.yun.constants.RedisConstant.*;

/**
 * @Description: 异步补货接口实现
 * @author liyunfeng31
 */
@Slf4j
@Component
public class ReplenishStockImpl implements ReplenishStock{


    @Resource
    private IConfig config;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private CouponRepository couponDao;

    /**
     * 奖品ID-消耗coupon数的MAP
     */
    public static AtomicLongMap<Long> CONSUME_COUPON_COUNT = AtomicLongMap.create();

    /**
     * 线程池
     */
    public static final ExecutorService SERVICE = Executors.newCachedThreadPool();


    public static final ExecutorCompletionService<Object> COMPLETION_SERVICE = new ExecutorCompletionService<>(SERVICE);


    /**
     * 异步处理补货
     */
    @PostConstruct
    public void handlerReplenish() {
        COMPLETION_SERVICE.submit(() -> {
            do {
                // todo rpoplpush
                List<Object> list = redisUtil.blPop(COUPON_REPLENISH_LIST);
                for (Object object : list) {
                    Long prizeId = (Long) object;
                    doReplenishStock(prizeId, Constant.FULL_STOCK >> 1);
                }
            } while (true);
        });
    }


    /**
     * lock锁和阻塞队列都保证了单线程补货
     * @param prizeId 奖品ID
     * @param num num
     * @return 补货数量
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int doReplenishStock(Long prizeId, int num){

        List<Long> noStocks = config. getNoStockSkuList(Long.class);
        List<Coupon> coupons = couponDao.findByIdLimit(prizeId, num);
        if(!CollectionUtils.isEmpty(noStocks) && noStocks.contains(prizeId)){
            return 0;
        }

        if(CollectionUtils.isEmpty(coupons)){
            noStocks.add(prizeId);
            config.publishConfig(NO_STOCK_SKU_LIST + JSON.toJSONString(noStocks));
            return 0;
        }
        List<Long> ids = new ArrayList<>();
        List<String> cps = new ArrayList<>();
        for (Coupon coupon : coupons) {
            ids.add(coupon.getCouponId());
            String code = coupon.getCode();
            String pwd = coupon.getPwd();
            String codePwd = StringUtils.isEmpty(pwd) ? code : code+ Constant.JOIN + pwd;
            cps.add(codePwd);
        }
        couponDao.updateCouponState(ids);
        redisUtil.lpush(COUPON_LIST + prizeId,cps);
        return ids.size();
    }

}
